using System;
using System.Collections.Generic;
using System.Text;

namespace BLF.WWW_WWW.Wiki
{
	/// <summary>
	/// Manages the Wiki's Recent Changes.
	/// </summary>
	public class RecentChanges {

		private static RecentChanges instance;

		/// <summary>
		/// Gets or sets the singleton instance of the RecentChanges object.
		/// </summary>
		public static RecentChanges Instance {
			get { return instance; }
			set { instance = value; }
		}

		private List<RecentChange> changes;
		private int threshold = 50; // The maximum number of changes
		private int cutSize = 20; // The number of changes that are removed when the threshold is reached

		/// <summary>
		/// Initializes a new instance of the <b>RecentChanges</b> class.
		/// </summary>
		public RecentChanges() {
			changes = new List<RecentChange>();
			Load();
		}

		private void Load() {
			lock(changes) {
				changes.Clear();

				// Load from file
				string data = Tools.LoadFile(Settings.RecentChangesFile).Replace("\r", "");
				string[] lines = data.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

				string[] fields;
				for(int i = 0; i < lines.Length; i++) {
					fields = lines[i].Split('|');
					Change c = Change.PageUpdated;
					switch(fields[4].ToUpper()) {
						case "U":
							c = Change.PageUpdated;
							break;
						case "D":
							c = Change.PageDeleted;
							break;
						case "R":
							c = Change.PageRolledBack;
							break;
						case "N":
							c = Change.PageRenamed;
							break;
					}
					changes.Add(new RecentChange(fields[0], fields[1].Replace("&#124;", "|"), DateTime.Parse(fields[2]), fields[3], c, fields.Length == 6 ? Tools.UnescapeString(fields[5]) : ""));
				}
			}
		}

		/// <summary>
		/// Gets all the Changes (not sorted).
		/// </summary>
		public RecentChange[] AllChanges {
			get { return changes.ToArray(); }
		}

		/// <summary>
		/// Adds a new change.
		/// </summary>
		/// <param name="page">The Page Name.</param>
		/// <param name="title">The Page Title.</param>
		/// <param name="dateTime">The Date/Time.</param>
		/// <param name="user">The User.</param>
		/// <param name="change">The Change.</param>
		/// <param name="descr">The Description (optional).</param>
		public void AddChange(string page, string title, DateTime dateTime, string user, Change change, string descr) {
			lock(changes) {
				changes.Add(new RecentChange(page, title, dateTime, user, change, descr));
				StringBuilder sb = new StringBuilder();
				sb.Append("\r\n");
				sb.Append(page);
				sb.Append("|");
				sb.Append(title.Replace("|", "&#124;"));
				sb.Append("|");
				sb.Append(dateTime.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss"));
				sb.Append("|");
				sb.Append(user);
				sb.Append("|");
				switch(change) {
					case Change.PageUpdated:
						sb.Append("U");
						break;
					case Change.PageDeleted:
						sb.Append("D");
						break;
					case Change.PageRolledBack:
						sb.Append("R");
						break;
					case Change.PageRenamed:
						sb.Append("N");
						break;
				}
				if(descr.Length > 0) {
					sb.Append("|");
					sb.Append(Tools.EscapeString(descr));
				}
				Tools.AppendFile(Settings.RecentChangesFile, sb.ToString());
				if(changes.Count >= threshold) {
					CutSize(changes.Count - cutSize);
				}
			}
		}

		/// <summary>
		/// Reduces the size of the "log" to the specified size, deleting old entries.
		/// </summary>
		/// <param name="size">The new Size.</param>
		public void CutSize(int size) {
			if(size >= changes.Count) return;

			int idx = changes.Count - size + 1;

			RecentChange[] ch = AllChanges;

			StringBuilder sb = new StringBuilder();

			for(int i = idx; i < ch.Length; i++) {
				sb.Append(ch[i].Page);
				sb.Append("|");
				sb.Append(ch[i].Title.Replace("|", "&#124;"));
				sb.Append("|");
				sb.Append(ch[i].DateTime.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss"));
				sb.Append("|");
				sb.Append(ch[i].User);
				sb.Append("|");
				switch(ch[i].Change) {
					case Change.PageUpdated:
						sb.Append("U");
						break;
					case Change.PageDeleted:
						sb.Append("D");
						break;
					case Change.PageRolledBack:
						sb.Append("R");
						break;
					case Change.PageRenamed:
						sb.Append("N");
						break;
				}
				if(i != ch.Length - 1) sb.Append("\r\n");
			}
			Tools.WriteFile(Settings.RecentChangesFile, sb.ToString());
			Load();
		}

	}

}
